package com.leoman.service.impl;

import com.leoman.controller.common.CommonController;
import com.leoman.core.Constant;
import com.leoman.dao.*;
import com.leoman.entity.*;
import com.leoman.exception.ParamErrorException;
import com.leoman.exception.UserNotFindException;
import com.leoman.exception.UserSealStatusException;
import com.leoman.service.CommentService;
import com.leoman.utils.DateUtils;
import com.leoman.utils.JsonUtil;
import com.leoman.utils.QiNiuUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartRequest;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;

/**
 * CommentServiceImpl
 * Created by 涂奕恒 on 2016/11/23 0023 下午 3:58.
 */
@Service
public class CommentServiceImpl implements CommentService {

    @Autowired
    private CommentDao commentDao;

    @Autowired
    private ImageDao imageDao;

    @Autowired
    private LetterDao letterDao;

    @Autowired
    private LetterAnnexSampleDao letterAnnexSampleDao;

    @Autowired
    private PaperDao paperDao;

    @Autowired
    private BroadcastDao broadcastDao;

    @Autowired
    private MindDao mindDao;

    @Autowired
    private CircleDao circleDao;

    @Autowired
    private UserDao userDao;

    @Autowired
    private PlacardDao placardDao;

    @Override
    public List<Comment> findAll() {
        return commentDao.findAll();
    }

    @Override
    public Page<Comment> find(int pageNum, int pageSize) {
        return commentDao.findAll(new PageRequest(pageNum - 1, pageSize, Sort.Direction.DESC, "id"));
    }

    @Override
    public Page<Comment> find(int pageNum) {
        return find(pageNum, Constant.PAGE_DEF_SIZE);
    }

    @Override
    public Comment getById(int id) {
        return commentDao.findOne(id);
    }

    @Override
    @Transactional
    public void deleteById(int id) {
        List<String> tempUrl = new ArrayList<>();

        Comment comment = commentDao.findOne(id);

        // 删除该纸条的所有图片
        List<Image> imageList = imageDao.findListByParams(id, Constant.SOURCE_TYPE_COMMENT);
        for (Image image : imageList) {
            tempUrl.add(image.getUrl());
            imageDao.delete(image);
        }

        // 删除评论中的语音文件
        if (comment.getVoiceTime() > 0) {
            tempUrl.add(comment.getContent());
        }

        commentDao.delete(id);

        for (String url : tempUrl) {
            QiNiuUtils.delete(url);
        }
    }

    @Override
    public Comment create(Comment comment) {
        return commentDao.save(comment);
    }

    @Override
    public Comment update(Comment comment) {
        return commentDao.save(comment);
    }

    @Override
    @Transactional
    public void deleteAll(int[] ids) {
        for (int id : ids) {
            deleteById(id);
        }
    }

    @Override
    public Page<Comment> iPageForApp(final Integer sourceId, final Integer sourceType, final Integer userId, final Integer type, Integer pageNum, Integer pageSize) {
        Integer[] info = CommonController.getPageParams(pageNum, pageSize);

        Page<Comment> page = commentDao.findAll(new Specification<Comment>() {
            @SuppressWarnings("ToArrayCallWithZeroLengthArrayArgument")
            @Override
            public Predicate toPredicate(Root<Comment> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                Predicate result = null;
                List<Predicate> predicateList = new ArrayList<>();

                if (null != sourceId) {
                    Predicate pre = cb.equal(root.get("sourceId").as(Integer.class), sourceId);
                    predicateList.add(pre);
                }

                if (null != sourceType) {
                    Predicate pre = cb.equal(root.get("sourceType").as(Integer.class), sourceType);
                    predicateList.add(pre);
                }

                if (null != userId) {
                    // type  类型，1，我发送的评论 2，别人对我的评论
                    if (null != type && type == 1) {
                        Predicate pre = cb.equal(root.get("user").get("id").as(Integer.class), userId);
                        predicateList.add(pre);
                    } else if (null != type && type == 2) {
                        Predicate pre = cb.equal(root.get("sourceUser").get("id").as(Integer.class), userId);
                        predicateList.add(pre);
                    }
                }

                if (predicateList.size() > 0) {
                    result = cb.and(predicateList.toArray(new Predicate[]{}));
                }

                if (result != null) {
                    query.where(result);
                }
                return query.getGroupRestriction();
            }

        }, new PageRequest(info[0] - 1, info[1], Sort.Direction.DESC, "isAdmin", "isTop", "id"));

        for (Comment comment : page.getContent()) {
            changeCommentInfo(comment);

            if (null != userId && comment.getIsRead().equals(Constant.USER_STATUS_NO)) {
                comment.setIsRead(Constant.USER_STATUS_YES);
                commentDao.save(comment);
            }
        }

        return page;
    }

    @Override
    public void addComment(Boolean isAdmin,
                           Integer userId,
                           Integer sourceId,
                           Integer sourceType,
                           Integer type,
                           Integer voiceTime,
                           String content,
                           Integer imgNum,
                           MultipartRequest multipartRequest) throws ParamErrorException, UserNotFindException, UserSealStatusException {
        if (StringUtils.isBlank(content) && (null == imgNum || imgNum == 0) && (null == voiceTime || voiceTime == 0)) {
            throw new ParamErrorException();
        }

        User user = UserServiceImpl.getUserInfo(userId, userDao);
        Comment comment = new Comment();

        switch (sourceType) {
            case 0:
                // 信件
                Letter letter = letterDao.findOne(sourceId);
                comment.setSourceUser(letter.getUser());
                break;
            case 1:
                // 纸条
                Paper paper = paperDao.findOne(sourceId);
                comment.setSourceUser(paper.getIsAdmin().equals(Constant.USER_STATUS_NO) ? paper.getUser() : null);
                break;
            case 2:
                // 广播
                Broadcast broadcast = broadcastDao.findOne(sourceId);
                comment.setSourceUser(broadcast.getIsAdmin().equals(Constant.USER_STATUS_NO) ? broadcast.getUser() : null);
                break;
            case 3:
                // 心事
                Mind mind = mindDao.findOne(sourceId);
                comment.setSourceUser(mind.getIsAdmin().equals(Constant.USER_STATUS_NO) ? mind.getUser() : null);
                break;
            case 4:
                // 兴趣圈
                Circle circle = circleDao.findOne(sourceId);
                comment.setSourceUser(circle.getIsAdmin().equals(Constant.USER_STATUS_NO) ? circle.getUser() : null);
                break;
        }

        comment.setUser(user);
        if (null != type && !type.equals(Constant.USER_STATUS_NO)) {
            comment.setIsReply(type);
        }

        if (null != voiceTime && voiceTime > 0) {
            MultipartFile voice = multipartRequest.getFile("voice");
            if (null != voice && voice.getSize() > 0) {
                comment.setVoiceUrl(QiNiuUtils.upload(voice));
            }
        }
        comment.setContent(content);
        comment.setVoiceTime(voiceTime);
        comment.setSourceId(sourceId);
        comment.setSourceType(sourceType);
        comment.setIsAdmin(isAdmin ? Constant.USER_STATUS_YES : Constant.USER_STATUS_NO);

        commentDao.save(comment);

        // 保存评论图片信息
        List<MultipartFile> list = multipartRequest.getFiles("image");

        Image image;
        for (MultipartFile file : list) {
            if (null != file && file.getSize() > 0) {
                image = new Image();
                image.setUrl(QiNiuUtils.upload(file));
                image.setSourceId(comment.getId());
                image.setSourceType(Constant.SOURCE_TYPE_COMMENT);

                imageDao.save(image);
            }
        }
    }

    @Override
    public List<Comment> findListBySourceIdAndType(Integer sourceId, Integer type) {
        return commentDao.findListBySourceIdAndType(sourceId, type);
    }

    @Override
    public Page<Comment> pageByParams(final String content,
                                      final String userName,
                                      final String startTime,
                                      final String endTime,
                                      final Integer sourceId,
                                      final Integer sourceType,
                                      Integer pageNum,
                                      Integer pageSize) {
        return commentDao.findAll(new Specification<Comment>() {
            @SuppressWarnings("ToArrayCallWithZeroLengthArrayArgument")
            @Override
            public Predicate toPredicate(Root<Comment> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                Predicate result = null;
                List<Predicate> predicateList = new ArrayList<>();

                if (StringUtils.isNotBlank(content)) {
                    Predicate pre = cb.like(root.get("content").as(String.class), "%" + content + "%");
                    predicateList.add(pre);
                }

                if (StringUtils.isNotBlank(userName)) {
                    Predicate pre = cb.like(root.get("user").get("nickName").as(String.class), "%" + userName + "%");
                    predicateList.add(pre);
                }

                if (StringUtils.isNotBlank(startTime)) {
                    try {
                        System.out.println(".");
                        Long startDate = DateUtils.stringToDateWithFormat(startTime, "yyyy-MM-dd hh:mm:ss").getTime();
                        predicateList.add(cb.gt(root.get("createTime").as(Long.class), startDate));
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                }

                if (StringUtils.isNotBlank(endTime)) {
                    try {
                        System.out.println(".");
                        Long endDate = DateUtils.stringToDateWithFormat(endTime, "yyyy-MM-dd hh:mm:ss").getTime();
                        predicateList.add(cb.lt(root.get("createTime").as(Long.class), endDate));
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                }

                if (null != sourceId) {
                    Predicate pre = cb.equal(root.get("sourceId").as(Integer.class), sourceId);
                    predicateList.add(pre);
                }

                if (null != sourceType) {
                    Predicate pre = cb.equal(root.get("sourceType").as(Integer.class), sourceType);
                    predicateList.add(pre);
                }

                if (predicateList.size() > 0) {
                    result = cb.and(predicateList.toArray(new Predicate[]{}));
                }

                if (result != null) {
                    query.where(result);
                }
                return query.getGroupRestriction();
            }

        }, new PageRequest(pageNum - 1, pageSize, Sort.Direction.DESC, "isAdmin", "isTop", "id"));
    }

    @Override
    public Integer deleteComment(Integer commentId) {
        try {
            deleteById(commentId);
            return 1;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    @Override
    @Transactional
    public Integer batchDelete(String ids) {
        try {
            Integer[] commentIds = JsonUtil.json2Obj(ids, Integer[].class);

            for (Integer commentId : commentIds) {
                deleteById(commentId);
            }
            System.out.println();
            return 1;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    @Override
    @Transactional
    public Integer saveComment(Integer sourceId, Integer type, String content, String tempAddImageIds, String tempDelImageIds) {
        try {
            Comment commentByAdmin = commentDao.findOneByParamsAndIsAdmin(sourceId, type);

            if (null != commentByAdmin) {
                deleteById(commentByAdmin.getId());
            }

            User user;
            switch (type) {
                case 0:
                    // 信件
                    user = letterDao.findOne(sourceId).getUser();
                    break;
                case 1:
                    // 纸条
                    user = paperDao.findOne(sourceId).getUser();
                    break;
                case 2:
                    // 广播
                    user = broadcastDao.findOne(sourceId).getUser();
                    break;
                case 3:
                    // 心事
                    user = mindDao.findOne(sourceId).getUser();
                    break;
                case 4:
                    // 兴趣圈
                    user = circleDao.findOne(sourceId).getUser();
                    break;
                default:
                    user = null;
                    break;
            }

            commentByAdmin = new Comment();
            commentByAdmin.setContent(content);
            commentByAdmin.setSourceId(sourceId);
            commentByAdmin.setSourceType(type);
            commentByAdmin.setSourceUser(user);
            commentByAdmin.setIsAdmin(Constant.USER_STATUS_YES);

            commentDao.save(commentByAdmin);

            // 保存评论图片
            Image image;
            String[] addImageIds = tempAddImageIds.split(",");
            for (String id : addImageIds) {
                if (StringUtils.isBlank(id)) {
                    continue;
                }
                image = imageDao.findOne(Integer.parseInt(id));
                image.setSourceId(commentByAdmin.getId());
                image.setSourceType(Constant.SOURCE_TYPE_COMMENT);

                imageDao.save(image);
            }

            String[] delImageIds = tempDelImageIds.split(",");
            for (String id : delImageIds) {
                if (StringUtils.isBlank(id)) {
                    continue;
                }
                image = imageDao.findOne(Integer.parseInt(id));
                QiNiuUtils.delete(image.getUrl());

                imageDao.delete(image);
            }

            return 1;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    @Override
    @Transactional
    public Integer saveComment(Integer sourceId, Integer type, String content, MultipartRequest multipartRequest) {
        Comment commentByAdmin = commentDao.findOneByParamsAndIsAdmin(sourceId, type);

        if (null != commentByAdmin) {
            deleteById(commentByAdmin.getId());
        }

        MultipartFile url = multipartRequest.getFile("url");

        User user = broadcastDao.findOne(sourceId).getUser();

        commentByAdmin = new Comment();
        commentByAdmin.setContent(content);
        if (null != url && url.getSize() > 0) {
            commentByAdmin.setVoiceUrl(QiNiuUtils.upload(url));
            commentByAdmin.setVoiceTime(QiNiuUtils.getVideoTime(url));
        }
        commentByAdmin.setSourceId(sourceId);
        commentByAdmin.setSourceType(type);
        commentByAdmin.setSourceUser(user);
        commentByAdmin.setIsAdmin(Constant.USER_STATUS_YES);

        commentDao.save(commentByAdmin);

        List<MultipartFile> imageList = new ArrayList<>();
        imageList.add(multipartRequest.getFile("cover1"));
        imageList.add(multipartRequest.getFile("cover2"));
        imageList.add(multipartRequest.getFile("cover3"));

        Image tempImage;
        for (MultipartFile image : imageList) {
            if (null != image && image.getSize() > 0) {
                tempImage = new Image();
                tempImage.setSourceId(commentByAdmin.getId());
                tempImage.setSourceType(Constant.SOURCE_TYPE_COMMENT);
                tempImage.setUrl(QiNiuUtils.upload(image));

                imageDao.save(tempImage);
            }
        }

        return 1;
    }

    @Override
    public Integer deleteAllComment(Integer sourceId, Integer sourceType) {
        try {
            List<Comment> commentList = commentDao.findListBySourceIdAndType(sourceId, sourceType);

            for (Comment comment : commentList) {
                deleteById(comment.getId());
            }

            return 1;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 加载评论附属信息
     *
     * @param comment 评论信息
     */
    private void changeCommentInfo(Comment comment) {
        switch (comment.getSourceType()) {
            case 0:
                // 信件
                Letter letter = letterDao.findOne(comment.getSourceId());

                comment.setCover(letterAnnexSampleDao.findOneByLetterAnnexId(letter.getStampId()).getCover());
                comment.setTitle(letter.getTitle());
                break;
            case 1:
                // 纸条
                Paper paper = paperDao.findOne(comment.getSourceId());

                comment.setSynopsis(paper.getContent());
                break;
            case 2:
                // 广播
                Broadcast broadcast = broadcastDao.findOne(comment.getSourceId());

                comment.setTitle(broadcast.getTitle());
                comment.setSynopsis(broadcast.getUrl());
                break;
            case 3:
                // 心事
                Mind mind = mindDao.findOne(comment.getSourceId());

                comment.setCover(mind.getCover());
                comment.setTitle(mind.getTitle());
                comment.setSynopsis(mind.getContent());
                break;
            case 4:
                // 兴趣圈
                Circle circle = circleDao.findOne(comment.getSourceId());

                comment.setCover(circle.getCover1());
                comment.setTitle(circle.getTitle());
                comment.setSynopsis(circle.getSynopsis());
                break;
            case 7:
                // 黑板
                Placard placard = placardDao.findOne(comment.getSourceId());

                comment.setCover(placard.getCover());
                comment.setTitle(placard.getTitle());
                comment.setSynopsis(placard.getSynopsis());
                break;
        }

        if (comment.getIsAdmin().equals(Constant.USER_STATUS_NO)) {
            comment.setUserId(comment.getUser().getId());
            comment.setAvatar(comment.getUser().getAvatar());
            comment.setNickName(comment.getUser().getNickName());
        }

        // 如果是回复，查询回复人昵称
        if (!comment.getIsReply().equals(Constant.USER_STATUS_NO)) {
            comment.setToUserNickName(userDao.findOne(comment.getIsReply()).getNickName());
        }

        comment.setImageList(imageDao.findListByParams(comment.getId(), Constant.SOURCE_TYPE_COMMENT));
    }
}